﻿// Imports
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.UI;

namespace Nickel
{

    /// <summary>
    /// Handles account actions
    /// </summary>
    public class Account : Page
    {

        /// <summary>
        /// Handles page load
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Event arguments</param>
        protected void Page_Load(object sender, EventArgs e)
        {

            // Get user
            Author user = Account.GetSignedInAuthor(Data, Request.Cookies[Settings.COOKIE_NAME]);

            #region Sign In

            // Signing in
            if (Request.Form[Constants.TYPE_SIGN_IN] != null)
            {

                // Initialize author
                Author author = null;

                // Sign in error string
                string strSignInError = string.Empty;

                // Check data
                if (Request.Form[Constants.INPUT_SIGN_IN_EMAIL] != null && Request.Form[Constants.INPUT_SIGN_IN_PASSWORD] != null)
                {

                    // Check lengths
                    if (Request.Form[Constants.INPUT_SIGN_IN_EMAIL].Trim().Length > 0 && Request.Form[Constants.INPUT_SIGN_IN_PASSWORD].Trim().Length > 0)
                    {

                        // Get author
                        author = Data.GetAuthorBySignIn(Request.Form[Constants.INPUT_SIGN_IN_EMAIL], StringHelper.Encrypt(Request.Form[Constants.INPUT_SIGN_IN_PASSWORD]));

                        // Not found
                        if (author == null) 
                            strSignInError = "{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.SIGN_IN_INVALID_INFO) + "\" }";

                    }
                    else
                    {

                        // Error if no data
                        strSignInError = "{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.SIGN_IN_MISSING_INFO) + "\" }";

                    }

                }
                else
                {

                    // Get author from cookie
                    author = GetSignedInAuthor(Data, Request.Cookies[Settings.COOKIE_NAME]);

                }

                // Error occurred
                if (strSignInError != string.Empty)
                {

                    // Write error
                    Response.Write(strSignInError);

                }
                else
                {

                    // No author found
                    if (author == null)
                    {

                        // Set string
                        string strForm = "<div id=\"signInForm\">" +
                            "<div class=\"tagFormLine\">" +
                            "<div class=\"tagFormLabel\">" + Labels.INPUT_SIGN_IN_EMAIL + "</div>" +
                            "<div class=\"tagFormInput\">" +
                            "<input type=\"text\" name=\"" + Constants.INPUT_SIGN_IN_EMAIL + "\" id=\"" + Constants.INPUT_SIGN_IN_EMAIL + "\" class=\"rightColumn\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_SIGN_IN + "');\" maxlength=\"320\" /></div>" +
                            "</div>" +
                            "<div class=\"tagFormLine\">" +
                            "<div class=\"tagFormLabel\">" + Labels.INPUT_SIGN_IN_PASSWORD + "</div>" +
                            "<div class=\"tagFormInput\">" +
                            "<input type=\"password\" name=\"" + Constants.INPUT_SIGN_IN_PASSWORD + "\" id=\"" + Constants.INPUT_SIGN_IN_PASSWORD + "\" class=\"rightColumn\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_SIGN_IN + "');\" maxlength=\"16\" /></div>" +
                            "</div>" +
                            "<div class=\"tagFormLine\">" +
                            "<div class=\"tagFormLabel\">" +
                            "</div>" +
                            "<div class=\"tagFormInput\">" +
                            "<input type=\"button\" name=\"signInSubmit\" id=\"signInSubmit\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_SIGN_IN + "');\" value=\"" + Labels.SUBMIT_SIGN_IN + "\" class=\"button\" /></div>" +
                            "</div>" +
                            "<a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_REGISTER + "')\" class=\"tagLink\">" + Labels.LINK_REGISTER + "</a><br />" +
                            "<a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_FORGOT_PASSWORD + "')\" class=\"tagLink\">" + Labels.LINK_FORGOT_PASSWORD + "</a>" +
                            "</div>";

                        // Write results
                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                    }
                    else
                    {

                        // Check if author is active
                        if (author.Active)
                        {

                            // Set cookie
                            HttpCookie cookie = new HttpCookie(Settings.COOKIE_NAME);
                            cookie.Values.Add(Constants.INPUT_EMAIL, author.Email);
                            cookie.Values.Add(Constants.INPUT_PASSWORD, author.Password);
                            cookie.Expires = DateTime.Now.AddDays(1);
                            Response.SetCookie(cookie);
                            cookie = null;

                            // Create links string
                            string strLinks = "<a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_PROFILE + "', '" + author.ID + "')\" class=\"tagLink\">" + Labels.LINK_PROFILE + "</a>" +
                                "<br /><a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_SIGN_OUT + "')\" class=\"tagLink\">" + Labels.LINK_SIGN_OUT + "</a>";

                            // Add admin links
                            if (author.Admin) strLinks = "<a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_ARTICLE + "')\" class=\"tagLink\">" + Labels.LINK_ARTICLE_NEW + "</a><br />" +
                                "<a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_AUTHOR_LIST + "')\" class=\"tagLink\">" + Labels.LINK_AUTHOR_LIST + "</a><br />" +
                                "<a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_TAGS + "')\" class=\"tagLink\">" + Labels.LINK_TAGS + "</a><br />" +
                                "<a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_ENCRYPT + "')\" class=\"tagLink\">" + Labels.LINK_ENCRYPT + "</a><br />" +
                                strLinks;

                            // Write links
                            Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strLinks) + "\" }");

                        }
                        else
                        {

                            // Build error string
                            strError = "Please <a onclick=\"onClick('" + Constants.SOURCE_LINK + "', '" + Constants.TYPE_ACTIVATE + "');\" style=\"text-decoration:underline;\">activate</a> your account";

                            // Inactive
                            Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(strError) + "\" }");

                        }

                    }

                }

                // Kill cookie if no author
                if (author == null) 
                    SignOut();

            }

            #endregion
            #region Sign Out

            // Log out
            if (Request.Form[Constants.TYPE_SIGN_OUT] != null)
            {

                // DO IT!
                SignOut();

                // Write response
                Response.Write("true");

            }

            #endregion
            #region Profile

            // Getting profile
            if (Request.Form[Constants.TYPE_PROFILE] != null)
            {

                // Must send valid ID
                if (Request.Form[Constants.INPUT_ID] != null && StringHelper.ValidGuid.IsMatch(Request.Form[Constants.INPUT_ID]))
                {

                    // Get ID
                    string strId = Request.Form[Constants.INPUT_ID];

                    // Get author
                    Author author = Data.GetAuthorById(strId);
                    if (author == null)
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.PROFILE_NOT_FOUND) + "\" }");

                    }
                    else
                    {

                        // Check login status
                        if (user != null)
                        {

                            // User must be admin or user editing their own profile
                            if (user.Admin || user == author)
                            {

                                // Updating
                                if (Request.Form[Constants.INPUT_SUBMIT] != null)
                                {

                                    // Prepare error string
                                    strError = string.Empty;

                                    // Flag to set password
                                    bool bSetPassword = false;

                                    // Validate name
                                    if (Request.Form[Constants.INPUT_NAME] == null || Request.Form[Constants.INPUT_NAME].Length < 1) 
                                        strError = Errors.NAME_EMPTY;
                                    if (strError == string.Empty)
                                    {
                                        Author authorByName = Data.GetAuthorByName(Request.Form[Constants.INPUT_NAME]);
                                        if (authorByName != null && authorByName.ID != strId) 
                                            strError = Errors.NAME_EXISTS;
                                        authorByName = null;
                                    }

                                    // Validate e-mail
                                    if (strError == string.Empty &&
                                        (Request.Form[Constants.INPUT_EMAIL] == null ||
                                        Request.Form[Constants.INPUT_EMAIL].Length < 1)) 
                                        strError = Errors.EMAIL_EMPTY;
                                    if (strError == string.Empty &&
                                        !StringHelper.ValidEmail.IsMatch(Request.Form[Constants.INPUT_EMAIL])) 
                                        strError = Errors.EMAIL_INVALID;
                                    if (strError == string.Empty)
                                    {
                                        Author authorByEmail = Data.GetAuthorByEmail(Request.Form[Constants.INPUT_EMAIL]);
                                        if (authorByEmail != null && authorByEmail.ID != strId) 
                                            strError = Errors.EMAIL_EXISTS;
                                        authorByEmail = null;
                                    }

                                    // Password fields filled out
                                    if ((Request.Form[Constants.INPUT_PASSWORD] != null &&
                                        Request.Form[Constants.INPUT_PASSWORD].Length > 0) ||
                                        (Request.Form[Constants.INPUT_PASSWORD_CONFIRM] != null &&
                                        Request.Form[Constants.INPUT_PASSWORD_CONFIRM].Length > 0))
                                    {

                                        // Validate password
                                        if (strError == string.Empty &&
                                            Request.Form[Constants.INPUT_PASSWORD_CONFIRM] == null) 
                                            strError = Errors.PASSWORD_CONFIRM_EMPTY;
                                        if (strError == string.Empty &&
                                            (Request.Form[Constants.INPUT_PASSWORD].Length < 6 ||
                                            Request.Form[Constants.INPUT_PASSWORD].Length > 16)) 
                                            strError = Errors.PASSWORD_LENGTH;
                                        if (strError == string.Empty &&
                                            (Request.Form[Constants.INPUT_PASSWORD].Length < 6 ||
                                            Request.Form[Constants.INPUT_PASSWORD_CONFIRM].Length > 16)) 
                                            strError = Errors.PASSWORD_CONFIRM_LENGTH;
                                        if (strError == string.Empty &&
                                            Request.Form[Constants.INPUT_PASSWORD] != Request.Form[Constants.INPUT_PASSWORD_CONFIRM]) 
                                            strError = Errors.PASSWORD_NO_MATCH;

                                        // Set password flag
                                        bSetPassword = strError == string.Empty;

                                    }

                                    // Error occurred
                                    if (strError != string.Empty)
                                    {

                                        // Write error
                                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(strError) + "\" }");

                                    }
                                    else
                                    {

                                        // Deleting author
                                        if (Request.Form[Constants.INPUT_DELETE] == "true")
                                        {

                                            // Only an admin may delete a separate author's account
                                            if (user.Admin && user != author)
                                            {

                                                // Record their name now so we can use it when they're gone
                                                string strName = author.Name;

                                                // Iterate through articles
                                                foreach (Article article in Data.Articles)
                                                {

                                                    // Article be this author
                                                    if (article.Author == author.ID)
                                                    {

                                                        // Remove article
                                                        Data.Articles.Remove(article);

                                                    }
                                                    else
                                                    {

                                                        // Remove comments
                                                        foreach (Comment comment in article.Comments) 
                                                            if (comment.Author == author.ID)
                                                                article.Comments.Remove(comment);

                                                    }

                                                }

                                                // Remove author
                                                Data.Authors.Remove(author);

                                                // Save data
                                                Data.Save();

                                                // Make name possessive
                                                strName += strName.Length > 1 ? strName.Substring(strName.Length - 1, 1).ToLower() == "s" ? "'" : "'s" : "";

                                                // Build confirmation message
                                                string strResult = "<div id=\"" + Constants.RESPONSE_ID + "\"><h1>" + Titles.AUTHOR_DELETED + "</h1>" +
                                                    "<p>" + strName + " reign of error comes to a close. " +
                                                    "All of " + strName + " comments and articles have been obliterated " +
                                                    "along with their account. It's time to move on with one less " +
                                                    "amongst our ranks.</p></div>";

                                                // Write confirmation message
                                                Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                                            }
                                            else
                                            {

                                                // Write error
                                                Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.UNAUTHORIZED_FATAL) + "\" }");

                                                // Kill cookie since this is a hack 
                                                // (can't be reached through forms)
                                                SignOut();

                                            }

                                        }
                                        else
                                        {

                                            // Set the basics
                                            author.HomePageUrl = Request.Form[Constants.INPUT_URL] == null ? string.Empty : Request.Form[Constants.INPUT_URL];
                                            author.ModifiedDateTime = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);
                                            author.Name = StringHelper.RemoveHtml(Request.Form[Constants.INPUT_NAME]);

                                            // Set password, if specified
                                            if (bSetPassword) 
                                                author.Password = StringHelper.Encrypt(Request.Form[Constants.INPUT_PASSWORD]);

                                            // Get current admin status before updating
                                            bool bAdmin = author.Admin;
                                            if (user.Admin && user != author) 
                                                author.Admin = Request.Form[Constants.INPUT_ADMIN] == "true";

                                            // Send e-mail if author has new admin status
                                            if (!bAdmin && author.Admin && user != author) 
                                                author.SendAdminNotification(strBaseUrl);

                                            // Get current e-mail address before updating
                                            string strEmail = author.Email;
                                            author.Email = Request.Form[Constants.INPUT_EMAIL].ToLower();

                                            // Set author's activation key and send it to them
                                            // if they're changing their e-mail address
                                            if (!author.Admin && strEmail != author.Email) 
                                                author.SendActivationKey(strBaseUrl);

                                            // Delete profile photo
                                            if (Request.Form[Constants.INPUT_DELETE_PHOTO] == "true" && File.Exists(Server.MapPath(@"~/uploads/profile/" + author.ID + ".jpg"))) 
                                                File.Delete(Server.MapPath(@"~/uploads/profile/" + author.ID + ".jpg"));

                                            // Save data
                                            Data.Save();

                                            // Start confirmation message
                                            string strResult = "<div id=\"" + Constants.RESPONSE_ID + "\">" +
                                                "<h1>" + Titles.PROFILE + "</h1>" +
                                                "<p>" + Responses.PROFILE;

                                            // Let 'em know whaddup if they changed their e-mail
                                            if (!author.Admin && strEmail != author.Email) strResult += Responses.PROFILE_EMAIL_CHANGED;

                                            // Close confirmation message
                                            strResult += "Click <a href=\"" + strBaseUrl + "\">here</a> to " +
                                                "return to the home page.</p></div>";

                                            // Write confirmation message
                                            Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                                            // Clean up
                                            author = null;

                                        }

                                    }

                                }
                                else
                                {

                                    // Build update profile form string
                                    string strForm = "<div id=\"" + Constants.RESPONSE_ID + "\">" +
                                        "<h1>" + Titles.PROFILE + "</h1>" +
                                        "<p>" + (author.Admin ? Instructions.PROFILE_ADMIN : Instructions.PROFILE) + "</p>" +
                                        "<div class=\"formLine\">" +
                                        "<div class=\"formLabel\">" + Labels.INPUT_NAME + "</div>" +
                                        "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_NAME + "\" id=\"" + Constants.INPUT_NAME + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_PROFILE + "');\" maxlength=\"128\" value=\"" + author.Name + "\" /></div>" +
                                        "</div>" +
                                        "<div class=\"formLine\">" +
                                        "<div class=\"formLabel\">" + Labels.INPUT_EMAIL + "</div>" +
                                        "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_EMAIL + "\" id=\"" + Constants.INPUT_EMAIL + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_PROFILE + "');\" maxlength=\"320\" value=\"" + author.Email + "\" /></div>" +
                                        "</div>" +
                                        "<div class=\"formLine\">" +
                                        "<div class=\"formLabel\">" + Labels.INPUT_PASSWORD + "</div>" +
                                        "<div class=\"formInput\"><input type=\"password\" name=\"" + Constants.INPUT_PASSWORD + "\" id=\"" + Constants.INPUT_PASSWORD + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_PROFILE + "');\" maxlength=\"16\" /></div>" +
                                        "</div>" +
                                        "<div class=\"formLine\">" +
                                        "<div class=\"formLabel\">" + Labels.INPUT_PASSWORD_CONFIRM + "</div>" +
                                        "<div class=\"formInput\"><input type=\"password\" name=\"" + Constants.INPUT_PASSWORD_CONFIRM + "\" id=\"" + Constants.INPUT_PASSWORD_CONFIRM + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_PROFILE + "');\" maxlength=\"16\" /></div>" +
                                        "</div>" +
                                        "<div class=\"formLine\">" +
                                        "<div class=\"formLabel\">" + Labels.INPUT_URL + "</div>" +
                                        "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_URL + "\" id=\"" + Constants.INPUT_URL + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_PROFILE + "');\" maxlength=\"320\" value=\"" + author.HomePageUrl + "\" /></div>" +
                                        "</div>";

                                    // User is admin
                                    if (user.Admin && user != author)
                                    {

                                        // Add admin check box
                                        strForm += "<div class=\"formLine\">" +
                                            "<div class=\"formLabel\">" + Labels.INPUT_ADMIN + "</div>" +
                                            "<div class=\"formInput\"><input type=\"checkbox\" name=\"" + Constants.INPUT_ADMIN + "\" id=\"" + Constants.INPUT_ADMIN + "\" value=\"true\" " + (author.Admin ? "checked" : string.Empty) + " class=\"checkbox\" /></div>" +
                                            "</div>";

                                        // Add delete check box
                                        strForm += "<div class=\"formLine\">" +
                                            "<div class=\"formLabel\">" + Labels.INPUT_DELETE + "</div>" +
                                            "<div class=\"formInput\"><input type=\"checkbox\" name=\"" + Constants.INPUT_DELETE + "\" id=\"" + Constants.INPUT_DELETE + "\" value=\"true\" /> " + Labels.INPUT_DELETE_WARNING + "</div>" +
                                            "</div>";

                                    }

                                    // Profile photos enabled
                                    if (Settings.PROFILE_IMAGE_ENABLED)
                                    {

                                        // Check for profile photo
                                        bool bPhoto = File.Exists(Server.MapPath(@"~/uploads/profile/" + author.ID + ".jpg"));
                                        if (bPhoto)
                                        {

                                            // Add delete photo line
                                            strForm += "<div class=\"formLine\">" +
                                                "<div class=\"formLabel\">" + Labels.INPUT_DELETE_PHOTO + "</div>" +
                                                "<div class=\"formInput\" style=\"margin-top:3px;\"><input type=\"checkbox\" name=\"" + Constants.INPUT_DELETE_PHOTO + "\" id=\"" + Constants.INPUT_DELETE_PHOTO + "\" value=\"true\" /></div>" +
                                                "</div>";

                                        }

                                        // Build upload bar
                                        string strUploadBar = Constants.PROFILE_UPLOAD_BAR;
                                        strUploadBar = strUploadBar.Replace("###authorId###", author.ID);
                                        strUploadBar = strUploadBar.Replace("###image###", bPhoto ?
                                            "<img src=\"" + strBaseUrl + "uploads/profile/" + author.ID + ".jpg\" />" :
                                            "<div id=\"noPhoto\" style=\"width:" +
                                                Settings.PROFILE_IMAGE_SIZE.ToString() + "px;height:" +
                                                Settings.PROFILE_IMAGE_SIZE.ToString() + "px;line-height:" +
                                                (Settings.PROFILE_IMAGE_SIZE / 4).ToString() + "px;\"><span class=\"tiny\"><br/>" +
                                                Labels.INPUT_NO_PHOTO + "</span></div>");
                                        strUploadBar = strUploadBar.Replace("###url###", strBaseUrl + Constants.ACTION_UPLOAD);

                                        // Add upload form and image
                                        strForm += "<div class=\"formLine\">" +
                                            "<div class=\"formLabel\">" + Labels.INPUT_PHOTO + "</div>" +
                                            "<div class=\"formInput\">" + strUploadBar + "</div>" +
                                            "</div>" +
                                            "<div style=\"height:" + (Settings.PROFILE_IMAGE_SIZE).ToString() + "px;\">&nbsp;</div>";

                                    }

                                    // Finish form
                                    strForm += "<div class=\"formLine\">" +
                                        "<div class=\"formLabel\">" +
                                        "<input type=\"hidden\" name=\"" + Constants.INPUT_ID + "\" id=\"" + Constants.INPUT_ID + "\" value=\"" + author.ID + "\" /> " +
                                        "<input type=\"button\" name=\"" + Constants.INPUT_SUBMIT + "\" id=\"" + Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_PROFILE + "', '" + author.ID + "');\" value=\"" + Labels.SUBMIT_PROFILE + "\" /></div>" +
                                        "<div id=\"" + Constants.TARGET_FORM_ERROR + "\"></div>" +
                                        "</div></div>";

                                    // Write registration form
                                    Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                                }

                            }
                            else
                            {

                                // Write error
                                Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.UNAUTHORIZED) + "\" }");

                            }

                        }
                        else
                        {

                            // Write error
                            Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.NOT_SIGNED_IN) + "\" }");

                        }

                        // Clean up
                        author = null;

                    }

                }
                else
                {

                    // Write error
                    Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.AUTHOR_ID_INVALID) + "\" }");

                }

                // Clean up
                user = null;

            }

            #endregion
            #region Register

            // Registering
            if (Request.Form[Constants.TYPE_REGISTER] != null)
            {

                // Submitting form
                if (Request.Form[Constants.INPUT_SUBMIT] != null)
                {

                    // Prepare error string
                    strError = string.Empty;

                    // Validate name
                    if (Request.Form[Constants.INPUT_NAME].Length < 1) 
                        strError = Errors.NAME_EMPTY;
                    if (strError == string.Empty && Data.GetAuthorByName(Request.Form[Constants.INPUT_NAME]) != null) 
                        strError = Errors.NAME_EXISTS;

                    // Validate e-mail
                    if (strError == string.Empty && Request.Form[Constants.INPUT_EMAIL].Length < 1) 
                        strError = Errors.EMAIL_EMPTY;
                    if (strError == string.Empty && Data.GetAuthorByEmail(Request.Form[Constants.INPUT_EMAIL]) != null) 
                        strError = Errors.EMAIL_EXISTS;
                    if (strError == string.Empty && !StringHelper.ValidEmail.IsMatch(Request.Form[Constants.INPUT_EMAIL])) 
                        strError = Errors.EMAIL_INVALID;

                    // Validate password
                    if (strError == string.Empty && Request.Form[Constants.INPUT_PASSWORD] == null) 
                        strError = Errors.PASSWORD_EMPTY;
                    if (strError == string.Empty && Request.Form[Constants.INPUT_PASSWORD_CONFIRM] == null) 
                        strError = Errors.PASSWORD_CONFIRM_EMPTY;
                    if (strError == string.Empty && (Request.Form[Constants.INPUT_PASSWORD].Length < 6 || Request.Form[Constants.INPUT_PASSWORD].Length > 16)) 
                        strError = Errors.PASSWORD_LENGTH;
                    if (strError == string.Empty && (Request.Form[Constants.INPUT_PASSWORD].Length < 6 || Request.Form[Constants.INPUT_PASSWORD_CONFIRM].Length > 16)) 
                        strError = Errors.PASSWORD_CONFIRM_LENGTH;
                    if (strError == string.Empty && Request.Form[Constants.INPUT_PASSWORD] != Request.Form[Constants.INPUT_PASSWORD_CONFIRM]) 
                        strError = Errors.PASSWORD_NO_MATCH;

                    // Error occurred
                    if (strError != string.Empty)
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(strError) + "\" }");

                    }
                    else
                    {

                        // Create new author
                        Author author = new Author();
                        author.ID = StringHelper.NewGuid;
                        author.ActivationKey = Data.Authors.Count == 0 ? "" : StringHelper.Encode(StringHelper.Encrypt(author.ID));
                        author.Admin = Data.Authors.Count == 0;
                        author.CreationDateTime = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);
                        author.Email = Request.Form[Constants.INPUT_EMAIL].ToLower();
                        author.HomePageUrl = "";
                        author.ModifiedDateTime = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);
                        author.Name = StringHelper.RemoveHtml(Request.Form[Constants.INPUT_NAME]);
                        author.Password = StringHelper.Encrypt(Request.Form[Constants.INPUT_PASSWORD]);

                        // Add to list
                        Data.Authors.Add(author);

                        // Save data
                        Data.Save();

                        // Declare result string
                        string strResult = string.Empty;

                        // This is the first author
                        if (Data.Authors.Count == 1)
                        {

                            // Set result text
                            strResult = "<div id=\"" + Constants.RESPONSE_ID + "\">" +
                                "<h1>" + Titles.REGISTER + "</h1>" +
                                "<p>Congratulations, you've just created the administrator account. " +
                                "If you haven't already, configure your mail server settings. Check the " +
                                "installation guide at <a href=\"http://nickel.codeplex.com/documentation\" " +
                                "target=\"_blank\">http://nickel.codeplex.com/documentation</a> for instructions.</p></div>";

                        }
                        else
                        {

                            // Set author's activation key and send it to them
                            author.SendActivationKey(strBaseUrl);

                            // Build confirmation message
                            strResult = "<div id=\"" + Constants.RESPONSE_ID + "\">" +
                                "<h1>" + Titles.REGISTER + "</h1>" +
                                "<p>Thank you! You should be receiving an e-mail " +
                                "with an activation link shortly. Click " +
                                "<a href=\"" + strBaseUrl + "\">here</a> " +
                                "to return to the home page.</p></div>";

                        }

                        // Write confirmation message
                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                        // Clean up
                        author = null;

                    }

                }
                else
                {

                    // Build registration form string
                    string strForm = "<div id=\"" + Constants.SOURCE_FORM + "\">" +
                        "<h1>" + Titles.REGISTER + "</h1>" +
                        "<p>" + Instructions.REGISTER + "</p>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">" + Labels.INPUT_NAME + "</div>" +
                        "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_NAME + "\" id=\"" + Constants.INPUT_NAME + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_REGISTER + "');\" maxlength=\"128\" /></div>" +
                        "</div>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">" + Labels.INPUT_EMAIL + "</div>" +
                        "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_EMAIL + "\" id=\"" + Constants.INPUT_EMAIL + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_REGISTER + "');\" maxlength=\"320\" /></div>" +
                        "</div>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">" + Labels.INPUT_PASSWORD + "</div>" +
                        "<div class=\"formInput\"><input type=\"password\" name=\"" + Constants.INPUT_PASSWORD + "\" id=\"" + Constants.INPUT_PASSWORD + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_REGISTER + "');\" maxlength=\"16\" /></div>" +
                        "</div>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">" + Labels.INPUT_PASSWORD_CONFIRM + "</div>" +
                        "<div class=\"formInput\"><input type=\"password\" name=\"" + Constants.INPUT_PASSWORD_CONFIRM + "\" id=\"" + Constants.INPUT_PASSWORD_CONFIRM + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_REGISTER + "');\" maxlength=\"16\" /></div>" +
                        "</div>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">" +
                        "<input type=\"button\" name=\"" + Constants.INPUT_SUBMIT + "\" id=\"" + Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_REGISTER + "');\" value=\"" + Labels.SUBMIT_REGISTER + "\" /></div>" +
                        "<div id=\"" + Constants.TARGET_FORM_ERROR + "\"></div>" +
                        "</div></div>";

                    // Write registration form
                    Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                }

            }

            #endregion
            #region Activate Request

            // Activation request
            if (Request.Form[Constants.TYPE_ACTIVATE] != null)
            {

                // E-mail received
                if (Request.Form[Constants.INPUT_EMAIL] != null)
                {

                    // Get author
                    Author author = Data.GetAuthorByEmail(Request.Form[Constants.INPUT_EMAIL]);
                    if (author != null)
                    {

                        // Author is active
                        if (author.Active)
                        {

                            // Write error
                            Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ACCOUNT_ACTIVATED) + "\" }");

                        }
                        else
                        {

                            // Create and send activation key
                            author.SendActivationKey(strBaseUrl);

                            // Build result string
                            string strResult = "<div id=\"" + Constants.RESPONSE_ID +
                                "\"><h1>" + Titles.ACTIVATE + "</h1>" +
                                "<p>" + Responses.ACTIVATE + "</p></div>";

                            // Write success message
                            Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                        }

                        // Clean up
                        author = null;

                    }
                    else
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.EMAIL_NOT_FOUND) + "\" }");

                    }

                }
                else
                {

                    // Build activation link form string
                    string strForm = "<div id=\"" + Constants.SOURCE_FORM + "\">" +
                        "<h1>" + Titles.ACTIVATE + "</h1>" +
                        "<p>" + Instructions.ACTIVATE + "</p>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">" + Labels.INPUT_EMAIL + "</div>" +
                        "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_EMAIL + "\" id=\"" + Constants.INPUT_EMAIL + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_ACTIVATE + "');\" maxlength=\"320\" />" +
                        "&nbsp;<input type=\"button\" name=\"" + Constants.INPUT_SUBMIT + "\" id=\"" + Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_ACTIVATE + "');\" value=\"" + Labels.SUBMIT_ACTIVATE + "\" /></div>" +
                        "</div>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">&nbsp;</div>" +
                        "<div id=\"" + Constants.TARGET_FORM_ERROR + "\"></div>" +
                        "</div></div>";

                    // Write form
                    Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                }

            }

            #endregion
            #region Forgot Password

            // Forgot password
            if (Request.Form[Constants.TYPE_FORGOT_PASSWORD] != null)
            {

                // E-mail received
                if (Request.Form[Constants.INPUT_EMAIL] != null)
                {

                    // Get author
                    Author author = Data.GetAuthorByEmail(Request.Form[Constants.INPUT_EMAIL]);
                    if (author != null)
                    {
                        // Send password
                        author.SendPassword();

                        // Build result string
                        string strResult = "<div id=\"" + Constants.RESPONSE_ID + "\"><h1>" +
                            Titles.FORGOT_PASSWORD + "</h1>" +
                            "<p>" + Responses.FORGOT_PASSWORD + "</p></div>";

                        // Write success message
                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                        // Clean up
                        author = null;

                    }
                    else
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.EMAIL_NOT_FOUND) + "\" }");

                    }

                }
                else
                {

                    // Build forgot password form string
                    string strForm = "<div id=\"" + Constants.SOURCE_FORM + "\">" +
                        "<h1>" + Titles.FORGOT_PASSWORD + "</h1>" +
                        "<p>" + Instructions.FORGOT_PASSWORD + "</p>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">" + Labels.INPUT_EMAIL + "</div>" +
                        "<div class=\"formInput\"><input type=\"text\" name=\"" + Constants.INPUT_EMAIL + "\" id=\"" + Constants.INPUT_EMAIL + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_FORGOT_PASSWORD + "');\" maxlength=\"320\" />" +
                        "&nbsp;<input type=\"button\" name=\"" + Constants.INPUT_SUBMIT + "\" id=\"" + Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_FORGOT_PASSWORD + "');\" value=\"" + Labels.SUBMIT_FORGOT_PASSWORD + "\" /></div>" +
                        "</div>" +
                        "<div class=\"formLine\">" +
                        "<div class=\"formLabel\">&nbsp;</div>" +
                        "<div id=\"" + Constants.TARGET_FORM_ERROR + "\"></div>" +
                        "</div></div>";

                    // Write form
                    Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                }

            }

            #endregion
            #region List Authors

            // Author list (admin only)
            if (Request.Form[Constants.TYPE_AUTHOR_LIST] != null)
            {

                // Check login status
                if (user != null && user.Admin)
                {

                    // Initialize authors string
                    string strAuthors = "<div id=\"list\"><p><strong>" + Instructions.AUTHOR_LIST + "</strong></p><div id=\"" + Constants.TARGET_LIST_ERROR + "\"></div>";

                    // Add links
                    int authorCount = Data.Authors.Count;
                    for (int i = 0; i < authorCount; i++) 
                        strAuthors += "<a onclick=\"onClick('" + Constants.SOURCE_LIST + "', '" + Constants.TYPE_PROFILE + "', '" + Data.Authors[i].ID + "');\">" + Data.Authors[i].Name + "</a><br />";

                    // Close paragraph
                    strAuthors += "</div>";

                    // Escape quotes and write
                    Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strAuthors) + "\" }");

                }
                else
                {

                    // Write error
                    Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ADMIN_REQUIRED) + "\" }");

                }

                // Clean up
                user = null;

            }

            #endregion
            #region Encrypt

            // String encrytor
            if (Request.Form[Constants.TYPE_ENCRYPT] != null)
            {

                // Must be admin
                if (user == null || !user.Admin)
                {

                    // Write error
                    Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.ADMIN_REQUIRED) + "\" }");

                }
                else
                {

                    // No values sent
                    if (Request.Form[Constants.INPUT_INPUT] == null)
                    {

                        // Build form string
                        string strForm = "<div id=\"form\">" +
                            "<h1>" + Titles.ENCRYPT + "</h1>" +
                            "<p>" + Instructions.ENCRYPT + "</p>" +
                            "<div class=\"formLine\">" +
                            "<div class=\"formLabel\">" + Labels.INPUT_INPUT + "</div>" +
                            "<div class=\"formInput\"><input type=\"password\" name=\"" + Constants.INPUT_INPUT + "\" id=\"" + Constants.INPUT_INPUT + "\" onkeyup=\"onKeyUp(event, '" + Constants.TYPE_ENCRYPT + "');\" maxlength=\"128\" />" +
                            "&nbsp;<input type=\"button\" name=\"" + Constants.INPUT_SUBMIT + "\" id=\"" + Constants.INPUT_SUBMIT + "\" onclick=\"onClick('" + Constants.SOURCE_FORM + "', '" + Constants.TYPE_ENCRYPT + "');\" value=\"" + Labels.SUBMIT_ENCRYPT + "\" /></div>" +
                            "<div class=\"formLine\">" +
                            "<div class=\"formLabel\">&nbsp;</div>" +
                            "<div id=\"" + Constants.TARGET_FORM_ERROR + "\"></div>" +
                            "</div></div>";

                        // Write form
                        Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strForm) + "\" }");

                    }
                    else
                    {

                        // Check length
                        if (Request.Form[Constants.INPUT_INPUT].Trim().Length > 0)
                        {

                            // Build confirmation message
                            string strResult = "<div id=\"" + Constants.RESPONSE_ID + "\"><h1>" + Titles.ENCRYPT + "</h1>" +
                                "<p>Your encrypted string reads:</p>" +
                                "<p>" + StringHelper.Encrypt(Request.Form[Constants.INPUT_INPUT]) + "</p>" +
                                "</div>";

                            // Write form
                            Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\" }");

                        }
                        else
                        {

                            // Write error
                            Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"" + StringHelper.JsonHtml(Errors.NOTHING_ENTERED) + "\" }");

                        }

                    }

                }

            }

            #endregion
            #region Subscribe

            // Author list (admin only)
            if (Request.Form[Constants.TYPE_SUBSCRIBE] != null)
            {

                // Check login status
                if (user != null)
                {

                    // Check required fields
                    if (Request.Form[Constants.INPUT_ARTICLE_ID] == null || Request.Form[Constants.INPUT_SUBSCRIBE] == null)
                    {

                        // Write error
                        Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"<span class=\"tiny\">" + StringHelper.JsonHtml(Errors.SUBSCRIBE) + "</a>\"}");

                    }
                    else
                    {

                        // Get article
                        Article article = Data.GetArticleById(Request.Form[Constants.INPUT_ARTICLE_ID]);
                        if (article == null)
                        {

                            // Write error
                            Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"<span class=\"tiny\">" + StringHelper.JsonHtml(Errors.SUBSCRIBE) + "</a>\"}");

                        }
                        else
                        {

                            // Find user in subscription
                            bool bSubscribed = false;
                            foreach (string subscriberID in article.Subscriptions) 
                                if (subscriberID == user.ID) 
                                    bSubscribed = true;

                            // Subscribed
                            if (bSubscribed)
                            {

                                // Remove
                                if (Request.Form[Constants.INPUT_SUBSCRIBE].Trim().ToLower() == "false") 
                                    article.Subscriptions.Remove(user.ID);
                                bSubscribed = false;

                            }
                            else
                            {

                                // Add
                                article.Subscriptions.Add(user.ID);
                                bSubscribed = true;

                            }

                            // Save
                            Data.Save();

                            // Replace link
                            string strResult = "<a onclick=\"onClick('" +
                                Constants.SOURCE_LINK + "', '" + Constants.TYPE_SUBSCRIBE + "', '" + article.ID +
                                "', " + (!bSubscribed).ToString().ToLower() + ");\" class=\"tiny\">" + (bSubscribed ? "Uns" : "S") + "ubscribe</a>";

                            // Write error
                            Response.Write("{ \"" + Constants.FIELD_SUCCESS + "\": \"" + StringHelper.JsonHtml(strResult) + "\"}");

                        }

                    }

                }
                else
                {

                    // Write error
                    Response.Write("{ \"" + Constants.FIELD_ERROR + "\": \"<span class=\"tiny\">" + StringHelper.JsonHtml(Errors.SUBSCRIBE) + "</a>\"}");

                }

            }

            #endregion

            // Clean up
            user = null;

        }

        /// <summary>
        /// Get signed in author
        /// </summary>
        /// <param name="blog">Blog data</param>
        /// <param name="cookie">Cookie to check</param>
        /// <returns>Author if found, null otherwise</returns>
        public static Author GetSignedInAuthor(Blog blog, HttpCookie cookie)
        {

            // Initialize return author
            Author author = null;

            // Get cookie
            if (cookie != null)
            {

                // Check values
                if (cookie[Constants.INPUT_EMAIL] != null && cookie[Constants.INPUT_PASSWORD] != null)
                {

                    // Get author
                    author = blog.GetAuthorBySignIn(cookie[Constants.INPUT_EMAIL], cookie[Constants.INPUT_PASSWORD]);

                    // Null author if inactive
                    if (author != null && !author.Active) author = null;

                }

                // Clean up
                cookie = null;

            }

            // Return author
            return author;

        }

        /// <summary>
        /// Sign out
        /// </summary>
        private void SignOut()
        {

            // Get cookie
            HttpCookie cookie = Response.Cookies[Settings.COOKIE_NAME];
            if (cookie != null)
            {

                // Kill cookie
                cookie.Expires = DateTime.Now.AddDays(-1d);
                Response.SetCookie(cookie);
                cookie = null;

            }

        }

    }

}
